package http

import (
	"context"
	"encoding/json"
	"fmt"
	"gcp-api-proxy/pkg/log"
	"net/http"

	"go.uber.org/zap"
)

type Req[T any] struct {
	*BaseReq
	Data *T
}

type Resp[T any] struct {
	StatusCode int
	Body       *T
}

func NewReqT[T any]() *Req[T] {
	return &Req[T]{
		Data: new(T),
	}
}

func NewRespT[T any](v *T) *Resp[T] {
	return &Resp[T]{
		Body: v,
	}
}

type DefaultHandler[T any, V any] struct {
	proxy   log.LoggerProxy
	handler func(context.Context, *Req[T]) (interface{}, error)
}

func NewHandler[T any, V any](proxy log.LoggerProxy, handler func(context.Context, *Req[T]) (interface{}, error)) *DefaultHandler[T, V] {
	h := &DefaultHandler[T, V]{
		proxy,
		handler,
	}
	return h
}

func NewDefaultHandler[T any](proxy log.LoggerProxy, handler func(context.Context, *Req[T]) (interface{}, error)) *DefaultHandler[T, string] {
	h := &DefaultHandler[T, string]{
		proxy,
		handler,
	}
	return h
}

func (s *DefaultHandler[T, V]) GetLogger() *zap.SugaredLogger {
	return s.proxy.GetLogger()
}
func (s *DefaultHandler[T, V]) Handle(ctx context.Context, req *BaseReq) (baseResp *BaseResp) {
	logger := s.proxy.GetLogger()
	// logger.Debugf("ChatMessage request: header:%v,body:%s", req.Header, string(req.Body))

	defer func() {
		if err := recover(); err != nil {
			logger.Errorf("handle path:%s, error:%v", req.RequestURI, err)
			baseResp = recoveryResult()
		}
	}()
	reqT := NewReqT[T]()
	err := json.Unmarshal(req.Body, reqT.Data)
	if err != nil {
		return processError(s.proxy, req.RequestURI, err)
	}
	reqT.BaseReq = req

	// if larkevent.ReqType(cardAction.Type) != larkevent.ReqTypeChallenge && !h.Config.SkipSignVerify {
	// 	err = h.VerifySign(ctx, req)
	// 	if err != nil {
	// 		return processError(ctx, h.Config.Logger, req.RequestURI, err)
	// 	}
	// }

	result, err := s.DoHandle(ctx, reqT)
	if err != nil {
		return processError(s.proxy, req.RequestURI, err)
	}
	return result
}

func (s *DefaultHandler[T, V]) DoHandle(ctx context.Context, req *Req[T]) (*BaseResp, error) {
	var err error

	// 校验行为执行器
	handler := s.handler
	if handler == nil {
		err = errNotFoundHandler
		return nil, err
	}

	// 执行事件行为处理器
	result, err := handler(ctx, req)
	if err != nil {
		return nil, err
	}

	header := map[string][]string{}
	header[ContentTypeHeader] = []string{DefaultContentType}
	if result == nil {
		baseResp := &BaseResp{
			Header:     header,
			Body:       []byte(fmt.Sprintf(WebhookResponseFormat, "ok")),
			StatusCode: http.StatusOK,
		}
		return baseResp, nil
	}

	var respBody []byte
	switch r := result.(type) {
	case string:
		respBody = []byte(r)
	case *Resp[V]:
		statusCode := r.StatusCode
		if statusCode == 0 {
			statusCode = http.StatusOK
		}

		b, err := json.Marshal(r.Body)
		if err != nil {
			return nil, err
		}

		baseResp := &BaseResp{
			Header:     header,
			Body:       b,
			StatusCode: statusCode,
		}
		return baseResp, nil
	default:
		s.proxy.GetLogger().Infof("get default branch on type %+v", r)
		respBody, err = json.Marshal(result)
		if err != nil {
			return nil, err
		}
	}

	baseResp := &BaseResp{
		Header:     header,
		Body:       respBody,
		StatusCode: http.StatusOK,
	}

	// statusCode := result.StatusCode
	// if statusCode == 0 {
	// 	statusCode = http.StatusOK
	// }

	// b, err := json.Marshal(result.Body)
	// if err != nil {
	// 	return nil, err
	// }

	// baseResp := &BaseResp{
	// 	Header:     header,
	// 	Body:       b,
	// 	StatusCode: statusCode,
	// }

	return baseResp, nil
}
